#include "openCV.h"
#include "common.h"
namespace compareImage {
	using v8::FunctionCallbackInfo;
	using v8::Isolate;
	using v8::Local;
	using v8::Object;
	using v8::String;
	using v8::Value;
	using v8::Exception;

	using namespace cv;
	using namespace std;

	//感知hash法
	void compareWithPHA(const FunctionCallbackInfo<Value>& args) {
		Isolate* isolate = args.GetIsolate();
		if (args.Length() < 2) {
			isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong number of arguments")));
			return;
		}

		if (!args[0]->IsString() || !args[1]->IsString()) {
			isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong arguments")));
			return;
		}

		v8::String::Utf8Value str1(args[0]->ToString());
		v8::String::Utf8Value str2(args[1]->ToString());
		string imgPath1 = string(*str1);
		string imgPath2 = string(*str2);
		cv::Mat image1 = imread(imgPath1, CV_LOAD_IMAGE_COLOR);
		cv::Mat image2 = imread(imgPath2, CV_LOAD_IMAGE_COLOR);
		string hash1 = pHashValue(image1);
		string hash2 = pHashValue(image2);
		int iDiffNum = HanmingDistance(hash1, hash2);
		int rv = -1;
		if (iDiffNum <= 5)  
			rv = 1; //很相似
		else if (iDiffNum > 10)  
    		rv = -1; //完全不相似
		else  
    		rv = 2; //有点相似
		args.GetReturnValue().Set(rv);
	}

	void compareWithArray(const FunctionCallbackInfo<Value>& args) {
		Isolate* isolate = args.GetIsolate();
		if (args.Length() < 2) {
			isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong number of arguments")));
			return;
		}

		if (!args[0]->IsString() || !args[1]->IsString()) {
			isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong arguments")));
			return;
		}

		v8::String::Utf8Value str1(args[0]->ToString());
		v8::String::Utf8Value str2(args[1]->ToString());
		string imgPath1 = string(*str1);
		string imgPath2 = string(*str2);
		cv::Mat image1 = imread(imgPath1, CV_LOAD_IMAGE_COLOR);
		cv::Mat image2 = imread(imgPath2, CV_LOAD_IMAGE_COLOR);

		if (image1.size() != image2.size()) {
			isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "The Two Image Size Not Equal")));
			return;
		}

		cv::Mat rvArray, rvArray1;
		double dissimilarity = -1;
	
		cv::compare(image1, image2, rvArray, cv::CMP_EQ);
		cv::cvtColor(rvArray, rvArray1, CV_BGRA2GRAY, 1);
		double percentage = cv::countNonZero(rvArray1);
		dissimilarity = (double)percentage / (double)(image1.rows * image1.cols);
		args.GetReturnValue().Set(dissimilarity);
	}

	void init(Local<Object> exports) {
		char out [21];
  		int n = sprintf(out, "%i.%i", CV_MAJOR_VERSION, CV_MINOR_VERSION);
  		exports->Set(Nan::New<String>("version").ToLocalChecked(), Nan::New<String>(out, n).ToLocalChecked());

		NODE_SET_METHOD(exports, "compareWithArray", compareWithArray);
		NODE_SET_METHOD(exports, "compareWithPHA", compareWithPHA);
	}
	NODE_MODULE(opencv_compare_image, init)

}  // namespace compareImage